package com.zqh.apicategoryquery.service.impl;

import com.alibaba.fastjson.JSON;
import com.zqh.apicategoryquery.redis.RedisUtil;
import com.zqh.apicategoryquery.service.ApiCategoryQueryService;
import com.zqh.myfmmall.clients.CategoryQueryClient;
import com.zqh.myfmmall.constants.RedisExpireTime;
import com.zqh.myfmmall.result.Result;
import com.zqh.myfmmall.rowbeans.vo.CategoryVo;
import com.zqh.myfmmall.rowbeans.vo.ProductVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Description :
 * @Author :kono淇杭哒、
 * @Create 2022-02-18 2:19
 */
@Service("apiCategoryQueryService")
public class ApiCategoryQueryServiceImpl implements ApiCategoryQueryService{
    @Autowired
    private CategoryQueryClient categoryQueryClient;

    @Autowired
    private RedisUtil redisUtil;


    @Override
    public Result retrieveVoByParentId(String parentId) {
        List<CategoryVo> categoryVo = (List<CategoryVo>) redisUtil.get("category-parentid:" + parentId);
        if (categoryVo != null) {
            return Result.success(categoryVo);
        }
        Result result = categoryQueryClient.retrieveByParentId(parentId);
        if (result.getSuccess()){
            redisUtil.setnx("category-parentid:" + parentId, result.getData());
        }
        return result;
    }

    @Override
    public Result retrieveFirstLevelCategoryVo() {
        Result result = null;
        //对应数据的基础key
        String redisKey = "categories-firstleval";
        List<CategoryVo> categorievos = (List<CategoryVo>) redisUtil.get(redisKey);
        //categories-firstleval
        if (categorievos != null) {
            result = Result.success(categorievos);
        }
        else {
            //二级缓存配合redis分布式锁解决缓存击穿问题
            List<CategoryVo> categorievosBackup = (List<CategoryVo>)redisUtil.get(redisKey);
            if (categorievosBackup != null) {
                try {
                    //使用缓存备份作为数据返回
                    result = Result.success(categorievosBackup);
                    //添加更新categories缓存的锁，从而只启动一个线程来更新缓存
                    boolean isAbsent = redisUtil.setnx(redisKey +"-lock", "1");
                    //加锁成功则进入进行缓存更新操作
                    if (isAbsent) {
                        Result firstLevalCategoryVosResult = categoryQueryClient.retrieveFirstLevalCategoryVos();
                        if (!firstLevalCategoryVosResult.getSuccess()){
                            return Result.internalServerError();
                        }
                        updateForRedisWithBackUp(redisKey,firstLevalCategoryVosResult.getData());
                    }
                } finally {
                    //释放锁
                    redisUtil.del(redisKey + "-lock");
                }
                //初始categories-list和categories-list-backup缓存数据(即第一次访问时进行)，但是这里可以通过缓存预热来优化，暂时先这样写
            }else{
                result = categoryQueryClient.retrieveFirstLevalCategoryVos();
                if (!result.getSuccess()){
                    return Result.internalServerError();
                }
                updateForRedisWithBackUp(redisKey,result.getData());
            }
        }
        return result;
    }

    @Override
    public Result retrieveAllCategorieVo(){
        Result result = null;
        //对应数据的基础key
        String redisKey = "categories-firstleval";
        List<CategoryVo> categorievos = (List<CategoryVo>) redisUtil.get(redisKey);
        //categories-list一级缓存不为空
        if (categorievos != null) {
            result = Result.success(categorievos);
        }
        else {
            //二级缓存配合redis分布式锁解决缓存击穿问题
            List<CategoryVo> categorievosBackup = (List<CategoryVo>)redisUtil.get(redisKey + "-backup");
            if (categorievosBackup != null) {
                //使用缓存备份作为数据返回
                result = Result.success(categorievosBackup);
                //添加更新categories缓存的锁，从而只启动一个线程来更新缓存
                boolean isAbsent = redisUtil.setnx(redisKey + "-lock", "1");
                //加锁成功则进入进行缓存更新操作
                if (isAbsent) {
                    try {
                        Result categoriesResult = categoryQueryClient.retrieveAllVo();
                        if (!categoriesResult.getSuccess()) {
                            return Result.internalServerError();
                        }
                        updateForRedisWithBackUp(redisKey,categoriesResult.getData());
                    } finally {
                        //释放锁
                        redisUtil.del(redisKey + "-lock");
                    }
                }
                //初始categories-list和categories-list-backup缓存数据(即第一次访问时进行)，但是这里可以通过缓存预热来优化，暂时先这样写
            }else{
                result = categoryQueryClient.retrieveAllVo();
                if (!result.getSuccess()){
                    return Result.internalServerError();
                }
                updateForRedisWithBackUp(redisKey,result.getData());
            }
        }
        return result;
    }

    /**
     * 功能描述:
     * 设置某一数据的redis一级和二级缓存
     *
     * @param
     * @param key
     * @return void
     * @author kono曾淇杭哒！
     * @date 2022/3/16 20:54
     */
    public void updateForRedisWithBackUp(String key,Object value){
        //更新缓存
        redisUtil.set(key,value,
                RedisExpireTime.CATEGORY.getTime(),RedisExpireTime.PRODUCT.getTimeUnit());
        redisUtil.set(key+"-backup",value,
                RedisExpireTime.CATEGORY.getTime() + 30,RedisExpireTime.PRODUCT.getTimeUnit());
    }
}
